iT邦幫忙

2022 iThome 鐵人賽

DAY 6
0

06 - Type Ahead

tags: JavaScript30

專案簡介

第六天要學習的是利用 fetch 串接 API,並利用新的事件 input 抓取使用者輸入的文字,再使用 正則表達式 篩選出 Data 中哪些地區有符合輸入字串

課程影片:JS30 06
導讀影片:Alex

初始文件

Github 檔案位置:06 - Type Ahead

網頁一開始的樣子如下

可以先去看看 最後的成品 如下

正式製作

流程

將程式的要求拆分步驟後,我們需要做的事情如下

  1. 設定好 search 的監聽事件
  2. 以 fetch 串接 API 獲得 Data
  3. 利用正則表達式篩選出 Data 中含有 input 字串的市或洲
  4. 利用正則表達式在數字上加上千分號
  5. 將整理好的資訊以寫好的 HTML + CSS 元素輸出於網頁上

設定好 search 的監聽事件

應用前幾天學到的東西,不一樣的是這次用了 input 事件 偵測輸入

function displayMatches() {
  console.log(this.value) // 確認什麼時候會觸發事件
}

const searchInput = document.querySelector('.search');
const suggestions = document.querySelector('.suggestions');

searchInput.addEventListener('input', displayMatches);

以 fetch 串接 API 獲得 Data

在這裡我們利用了 fetch 去串接 API,再利用 json() 將 JSON 檔解析為 JS 物件,並利用 解構賦值 將 Data 傳至我們的 List 中

const endpoint = 'https://gist.githubusercontent.com/Miserlou/c5cd8364bf9b2420bb29/raw/2bf258763cdddd704f8ffd3ea9a3e81d25e2c6f6/cities.json';

const cities = [];
fetch(endpoint)
 .then(item => item.json())
 .then(data => cities.push(...data));
console.log(cities);

利用正則表達式篩選出 Data 中含有 input 字串的市和洲

在這裡我們用到了之前剛學的 filter,不同的是這次用了 正則表達式match 做搭配

new RegExp 會幫助我們建立一個正則表達式的物件,其中 gi 是參數,g 的意思是全域搜尋,i則是不區分大小寫

match() 會依造我們設立的規則去搜尋 Data,如果存在就會回傳 true

function findMatches(wordToMatch, cities) {
  return cities.filter(place => {
    // g:全域搜尋 
    // i:不分大小寫
    const regex = new RegExp(wordToMatch, 'gi');
    return place.city.match(regex) || place.state.match(regex);
  })
}

利用正則表達式在數字上加上千分號

在這裡可以利用偷懶的方式直接使用 toLocaleString() 函數

function numberWithCommas(x) {
  // 由於 x 為字串,要先 * 1 轉型為數字
  return (x * 1).toLocaleString();
}

然後我們要學習的是正則表達式的應用
成品如下,replace 做的事情是將正則表達式找到的地方替換為 ,

function numberWithCommas(x) {
  // 由於 x 為字串,要先 * 1 轉型為數字
  // return (x * 1).toLocaleString();
  return x.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ',');
}

將整理好的資訊以寫好的 HTML + CSS 元素輸出於網頁上

統整完資訊之後,我們將所有資訊包進 HTML 語法的字串中,並以 suggestions.innerHTML 渲染進網頁中

const html = matchArray.map(place => { 
    const regex = new RegExp(this.value, 'gi'); 
    const cityName = place.city.replace(regex, `<span class="hl">${this.value}</span>`); // 在符合正則表達式的字上加上選取框
    const stateName = place.state.replace(regex, `<span class="hl">${this.value}</span>`); // 在符合正則表達式的字上加上選取框
    return `
      <li>
        <span class="name">${cityName}, ${stateName}</span>
        <span class="population">${numberWithCommas(place.population)}</span>
      </li>
    `;
    }).join(''); 
    suggestions.innerHTML = html; 
}

最後程式碼

JS

const endpoint = 'https://gist.githubusercontent.com/Miserlou/c5cd8364bf9b2420bb29/raw/2bf258763cdddd704f8ffd3ea9a3e81d25e2c6f6/cities.json';

const cities = [];
fetch(endpoint)
 .then(item => item.json())
 .then(data => cities.push(...data));
console.log(cities);

function findMatches(wordToMatch, cities) {
  return cities.filter(place => {
    // g:全域搜尋 
    // i:不分大小寫
    const regex = new RegExp(wordToMatch, 'gi');
    return place.city.match(regex) || place.state.match(regex);
  })
}

function numberWithCommas(x) {
  // 由於 x 為字串,要先 * 1 轉型為數字
  // return (x * 1).toLocaleString();
  return x.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ',');
}

function displayMatches() {
  //console.log(this.value) // 確認什麼時候會觸發事件
  const matchArray = findMatches(this.value, cities);
  //console.log(matchArray); // 確認正則表達式結果正確
  const html = matchArray.map(place => { 
    const regex = new RegExp(this.value, 'gi'); 
    const cityName = place.city.replace(regex, `<span class="hl">${this.value}</span>`); // 在符合正則表達式的字上加上選取框
    const stateName = place.state.replace(regex, `<span class="hl">${this.value}</span>`); // 在符合正則表達式的字上加上選取框
    return `
      <li>
        <span class="name">${cityName}, ${stateName}</span>
        <span class="population">${numberWithCommas(place.population)}</span>
      </li>
    `;
  }).join(''); 
  suggestions.innerHTML = html; 
}

const searchInput = document.querySelector('.search');
const suggestions = document.querySelector('.suggestions');

searchInput.addEventListener('input', displayMatches);

完成結果圖

最後的成品

結語

以上是第六天的製作紀錄,如有錯誤或不足的地方還請多多指教 >.<

[ Alex 宅幹嘛 ] 深入淺出 Javascript30 快速導覽Day 6:Type Ahead
Ajax Type Ahead with fetch() - #JavaScript30 6/30
MDN Web Docs


上一篇
JS30 -> 05 - Flex Panel Gallery
下一篇
JS30 -> 07 - Array Cardio Day 2
系列文
剛接觸前端一個月的小白 - JavaScript30 挑戰筆記30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言